from copy import deepcopy
from sys import argv
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *


class MyPyOpenGLTest:
    # 初始化OpenGL环境，指定显示模式以及用于绘图的函数
    def __init__(self, width=640, height=480,
                 title='PyOpenGL可调整的二维Bezier曲线'.encode('gbk')):
        glutInit(argv)
        glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE)
        glutInitWindowSize(width, height)
        glutInitWindowPosition(400, 200)
        glutCreateWindow(title)
        glutDisplayFunc(self.draw)
        glutReshapeFunc(self.reshape)
        glutIdleFunc(self.draw)
        glutMouseFunc(self.mouse_downup)
        glutMotionFunc(self.mouse_move)
        # 初始化窗口背景为白色
        glClearColor(1, 1, 1, 1)

        # 指定三次贝塞尔曲线的4个控制点坐标
        self.control_points = [(40, 20, 0), (50, 130, 0),
                               (120, 150, 0), (245, 30, 0)]
        # 鼠标控制的控制点序号
        self.index = None

    def reshape(self, w, h):
        glViewport(0, 0, w, h)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        # 设置世界黄口的左下角x坐标，右上角x坐标、左下角y坐标、右下角y坐标
        gluOrtho2D(0, w, h, 0)

    def mouse_downup(self, button, state, x, y):
        if button != GLUT_LEFT_BUTTON:
            return
        if state == GLUT_DOWN:
            current_position = (x, y, 0)
            check = lambda i, j: (i - j) ** 2
            for index, point in enumerate(self.control_points):
                if sum(map(check, point, current_position)) < 10:
                    self.index = index
                    break
        elif state == GLUT_UP:
            self.index = None

    def mouse_move(self, x, y):
        if self.index is None:
            return
        self.control_points[self.index] = (x, y, 0)


    def getBezier(self, P0, P1, P2, P3, t):
        points = deepcopy(self.control_points)
        func = lambda i, j:(1-t)*i + t*j
        for p in range(3):
            for q in range(3-p):
                points[q] = tuple(map(func, points[q], points[q+1]))
        return points[0]

    def draw(self):
        glClear(GL_COLOR_BUFFER_BIT)
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

        # 绘制控制点
        glColor3f(1, 0, 0)
        glPointSize(8)
        glBegin(GL_POINTS)
        for point in self.control_points:
            glVertex3fv(point)
        glEnd()

        # 绘制控制多边形
        glColor3f(0.5, 0.5, 0.5)
        glLineWidth(2)
        glBegin(GL_LINE_STRIP)
        for point in self.control_points:
            glVertex3fv(point)
        glEnd()

        # 绘制Bezier曲线
        glColor3f(0.0, 0.0, 0.0)
        glLineWidth(3)
        glBegin(GL_LINE_STRIP)
        for i in range(1001):
            t = i / 1000
            p = self.getBezier(*self.control_points, t)
            glVertex3fv(p)
        glEnd()

        glutSwapBuffers()

    # 消息主循环
    def mainloop(self):
        glutMainLoop()


if __name__ == '__main__':
    # 创建窗口对象，启动消息主循环
    MyPyOpenGLTest().mainloop()
